import { domain } from './api.js';
import WxValidate from './WxValidate.js';
import WxRequest from './request/index';

/**
 * 深度合并
 * @param arguments
 */
const extend = function () {
    let i;
    let o;
    let l = Object.keys(arguments).length;
    if (l <= 1) {
        return arguments[0];
    }
    for (i in arguments) {
        if (i != 0 && i < l) {
            o = Object.assign(arguments[0], arguments[i]);
        }
    }
    return o;
};

/**
 * wx.request 网络请求封装
 */
const http = {
    /**
     * 网络请求方法
     * @params {string} type 内部封装方法类型
     * @params {string} url 请求地址
     * @params {object} config 请求配置
     * @params {boolean} loadStyle 请求默认提示
     */
    request(type, url, config, loadStyle = true) {
        let mode;
        let options = {
            url: null,
            request: null,
            requestError: null,
            response: null,
            responseError: null
        };
        options = extend({}, options, config);

        //系统信息
        let systemInfo = uni.getSystemInfoSync();
        let sys = {
            device: `WechatMini ${systemInfo.platform}`,
            SDKVersion: systemInfo.SDKVersion,
            devicecode: systemInfo.model.replace(/<\/?[^>]*>/, ''),
            version: systemInfo.version
        };
        options.data.sys = JSON.stringify(sys);
        const request = new WxRequest({
            baseURL: options.url != null ? options.url : domain
        });
        if (loadStyle) {
            request.interceptors.use({
                // 请求数据
                request(request) {
                    $loading();
                    return request;
                },
                // 请求失败
                requestError(requestError) {
                    uni.hideLoading();
                    return Promise.reject(requestError);
                },
                // 响应数据
                response(response) {
                    uni.hideLoading();
                    return response;
                },
                // 响应失败
                responseError(responseError) {
                    uni.hideLoading();
                    return Promise.reject(responseError);
                }
            });
        } else {
            request.interceptors.use({
                // 请求数据
                request(request) {
                    if (options.request) {
                        options.request();
                    }
                    return request;
                },
                // 请求失败
                requestError(requestError) {
                    if (options.requestError) {
                        options.requestError();
                    }
                    return Promise.reject(requestError);
                },
                // 响应数据
                response(response) {
                    if (options.response) {
                        options.response();
                    }
                    return response;
                },
                // 响应失败
                responseError(responseError) {
                    if (options.responseError) {
                        options.responseError();
                    }
                    return Promise.reject(responseError);
                }
            });
        }
        switch (type) {
            case 'get':
                mode = request.getRequest(url, options);
                break;
            case 'post':
                mode = request.postRequest(url, options);
                break;
            case 'put':
                mode = request.putRequest(url, options);
                break;
            case 'delete':
                mode = request.deleteRequest(url, options);
                break;
        }
        return new Promise((resolve, reject) => {
            mode.then((res) => {
                if (res.data) {
                    if (!res.data.code) {
                        resolve(res);
                    } else {
                        reject(res);
                        $toast(res.data.errmsg);
                    }
                } else {
                    $toast('未获取到数据');
                }
            }).catch((res) => {
                reject(res);
            });
        });
    },
    get(url, config = {}, loadStyle = true) {
        return this.request('get', url, config, loadStyle);
    },
    post(url, config = {}, loadStyle = true) {
        return this.request('post', url, config, loadStyle);
    },
    put(url, config = {}, loadStyle = true) {
        return this.request('put', url, config, loadStyle);
    },
    delete(url, config = {}, loadStyle = true) {
        return this.request('delete', url, config, loadStyle);
    }
};

/**
 * 异步函数转成 promise
 * 调用方式：
 * promisify(original)(opt).then(res=>{ 成功code }).catch(res=>{ 失败code })
 * @original wx.xxx 方法名(必填)
 * @opt 对应参数 可以为空
 */
const promisify = (original) => {
    return function (opt = {}) {
        return new Promise((resolve, reject) => {
            opt = Object.assign(
                {
                    success: resolve,
                    fail: reject
                },
                opt
            );
            original(opt);
        });
    };
};

/**
 * promise 结束的回调函数（调用成功、失败都会执行）
 */
Promise.prototype.finally = function (callback) {
    const thisPF = this.constructor;
    return this.then(
        (res) => thisPF.resolve(callback()).then(() => res),
        (rej) =>
            thisPF.resolve(callback()).then(() => {
                throw rej;
            })
    );
};

/***
 * @计算优化
 * @param {Object} a
 * @param {Object} b
 */
const countMode = {
    add(a, b) {
        var c;
        var d;
        var e;
        try {
            c = a.toString().split('.')[1].length;
        } catch (f) {
            console.log('CatchClause', f);
            console.log('CatchClause', f);
            c = 0;
        }
        try {
            d = b.toString().split('.')[1].length;
        } catch (f) {
            console.log('CatchClause', f);
            console.log('CatchClause', f);
            d = 0;
        }
        e = Math.pow(10, Math.max(c, d));
        return (this.mul(a, e) + this.mul(b, e)) / e;
    },
    sub(a, b) {
        var c;
        var d;
        var e;
        try {
            c = a.toString().split('.')[1].length;
        } catch (f) {
            console.log('CatchClause', f);
            console.log('CatchClause', f);
            c = 0;
        }
        try {
            d = b.toString().split('.')[1].length;
        } catch (f) {
            console.log('CatchClause', f);
            console.log('CatchClause', f);
            d = 0;
        }
        e = Math.pow(10, Math.max(c, d));
        return (this.mul(a, e) - this.mul(b, e)) / e;
    },
    mul(a, b) {
        var c = 0;
        var d = a.toString();
        var e = b.toString();
        try {
            c += d.split('.')[1].length;
        } catch (f) {
            console.log('CatchClause', f);
            console.log('CatchClause', f);
        }
        try {
            c += e.split('.')[1].length;
        } catch (f) {
            console.log('CatchClause', f);
            console.log('CatchClause', f);
        }
        return (Number(d.replace('.', '')) * Number(e.replace('.', ''))) / Math.pow(10, c);
    },
    div(a, b) {
        var c;
        var d;
        var e = 0;
        var f = 0;
        try {
            e = a.toString().split('.')[1].length;
        } catch (g) {
            console.log('CatchClause', g);
            console.log('CatchClause', g);
        }
        try {
            f = b.toString().split('.')[1].length;
        } catch (g) {
            console.log('CatchClause', g);
            console.log('CatchClause', g);
        }
        c = Number(a.toString().replace('.', ''));
        d = Number(b.toString().replace('.', ''));
        return this.mul(c / d, Math.pow(10, f - e));
    }
};

/**
 * 对象转url参数
 * @param {objetc} params 格式{key: value}
 * @param {boolean} bool是否带参数
 */
const urlEncode = function (params, bool = false) {
    var url = '';
    var t = typeof params;
    if (t == undefined || t == null) {
        return url;
    }
    if (t == 'object') {
        url = Object.keys(params)
            .map((key) => {
                return key + '=' + params[key];
            })
            .join('&');
    } else if (t == 'string' || t == 'number' || t == 'boolean') {
        url = params;
    }
    if (bool && url != '') {
        url = '?' + url;
    }
    return url;
};

/**
 * 过滤文本空格
 * @param value选要过滤空格的值
 */
const $empty = (value) => {
    return value.replace(/\s/g, '');
};

/**
 * 序列化
 * @param value
 * @returns {string}
 */
const serialize = (value) => {
    if (typeof value === 'string') {
        return value;
    }
    return JSON.stringify(value);
};

/**
 * 反序列化
 * @param value
 * @returns {*}
 */
const deserialize = (value) => {
    if (typeof value !== 'string') {
        return undefined;
    }
    try {
        return JSON.parse(value);
    } catch (err) {
        console.log('CatchClause', err);
        console.log('CatchClause', err);
        return value || undefined;
    }
};

/**
 * 获取标签data
 */
const selectElements = function (type, elements) {
    let data = {};
    this.el = elements;
    this.query = uni.createSelectorQuery();
    switch (type) {
        //选择标签
        case 'select':
            data = this.select();
            break;
    }
    return data;
};
selectElements.prototype.select = function () {
    let value = '';
    let mode = '';
    const that = this;
    const argu = that.el.split(',');
    const leng = Object.keys(argu).length;
    //重新
    argu.forEach((item, i) => {
        i < leng - 1 ? (value += item + ',') : (value += item);
    });
    leng > 1 ? (mode = that.query.selectAll(value)) : (mode = that.query.select(value));
    return {
        value: leng,
        various: mode
    };
};

/**
 * 本地缓存
 * @method
 */
const storage = {
    //添加
    set(key, value, cb) {
        //序列化值
        promisify(uni.setStorage)({
            key: key,
            data: serialize(value)
        }).then(() => {
            if (cb) {
                cb();
            }
        });
    },
    //获取
    get(key) {
        return new Promise((resolve, reject) => {
            promisify(uni.getStorage)({
                key: key
            })
                .then((res) => {
                    //反序列化值
                    res = deserialize(res.data);
                    resolve(res);
                })
                .catch((res) => {
                    reject(res);
                });
        });
    },
    //修改
    modify(original) {
        const that = this;
        return function (opt = {}) {
            return new Promise((resolve, reject) => {
                that.get(original)
                    .then((res) => {
                        //合并对象
                        res = extend({}, res, opt);
                        resolve(res);
                    })
                    .catch((res) => {
                        reject(res);
                    });
            });
        };
    },
    //删除
    remove(key) {
        return new Promise((resolve, reject) => {
            promisify(uni.removeStorage)({
                key: key
            })
                .then((res) => {
                    resolve(res);
                })
                .catch((res) => {
                    reject(res);
                });
        });
    }
};
const $query = {
    /**
     * 查找对象
     * @params {string} elements 需要查找的名称
     * @params {functin} callback 查找成功回调
     */
    select: function (elements, callback) {
        const data = new selectElements('select', elements);
        const various = data.various.boundingClientRect();
        various.exec((res) => {
            if (callback) {
                callback(res[0], data.value);
            }
        });
    }
};
const Validate = {
    /**
     * 生成验证表单规则
     * @params {string} elements 需要查找的名称
     * @params {functin} callback 查找成功回调
     */
    rules: (elements, callback) => {
        $query.select(elements, function (res, i) {
            let rules = {};
            let msg = {};
            if (i <= 1) {
                rules[res.id] = res.dataset.rules;
                msg[res.id] = res.dataset.rulesmsg;
            } else {
                res.forEach((item, i) => {
                    rules[item.id] = item.dataset.rules;
                    msg[item.id] = item.dataset.rulesmsg;
                });
            }
            const selfValidate = new WxValidate(rules, msg);

            /**
             * 自定义验证方式
             */
            //不可中文
            selfValidate.addMethod(
                'chinese',
                (value, param) => {
                    return /^[u4E00-u9FA5]+$/.test(value);
                },
                '不能包含中文'
            );
            if (callback) {
                callback(selfValidate);
            }
        });
    },
    /**
     * 获取对象rules data参数
     * @params {object} self 调用页面this对象
     * @params {object} rules Validate生成验证规则
     * @params {object} value 需要验证的值
     * @params {function} callback 验证成功回调
     * @params {boolean} limit 是否显示错误
     */
    check: (self, rules, value, callback, limit = true) => {
        const result = rules.checkForm(value);
		console.log('打印：result~~~~~~',result)
        if (!result) {
            const error = rules.validationErrors();
            if (limit) {
                error.forEach((item, i) => {
                    self.setData({
                        [item.param + 'Error']: item.msg
                    });
                });
            }
            if (callback) {
                callback(result, error);
            }
            return false;
        }
        if (callback) {
            callback(result);
        }
    }
};

/**
 * toast 提示
 * @params {string} text 提示文字
 * @params {object} param 相关配置
 */
const $toast = (text, param = {}) => {
    return new Promise((resolve, reject) => {
        let opt = extend(
            {},
            {
                icon: 'none',
                mask: true,
                times: 1500
            },
            param
        );
        promisify(uni.showToast)({
            title: text,
            icon: opt.icon,
            duration: opt.times
        })
            .then(() => {
                setTimeout(() => {
                    uni.hideToast();
                    resolve();
                }, opt.times);
            })
            .catch(() => {
                reject();
            });
    });
};

/**
 * loading 加载
 * @params {object} param 加载配置
 */
const $loading = (param = {}) => {
    return new Promise((resolve, reject) => {
        let opt = extend(
            {},
            {
                title: '加载中...',
                mask: true,
                times: 2000
            },
            param
        );
        promisify(uni.showLoading)({
            title: opt.title,
            mask: opt.mask
        })
            .then(() => {
                resolve();
            })
            .catch(() => {
                reject();
            });
    });
};

module.exports = {
    Validate: Validate,
    extend: extend,
    http: http,
    countMode: countMode,
    promisify: promisify,
    urlEncode: urlEncode,
    serialize: serialize,
    deserialize: deserialize,
    storage: storage,
    $query: $query,
    $empty: $empty,
    $toast: $toast,
    $loading: $loading
};
